/*
 * Copyright (c) 2010 MoSync AB
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

// Screen that displays a user interface for downloading Lua apps.

#include <MAInterpreter/LuaInterpreter.h>
#include <MAInterpreter/System.h>

#include <MAUI/Layout.h>
//#include <MAUI/Image.h>
#include <MAUI/ListBox.h>
#include <MAUI/Label.h>
#include <MAUI/EditBox.h>

#include <wchar.h>
#include <conprint.h>

extern "C" {
#include <lua/lua.h>
#include <lua/lualib.h>
#include <lua/lauxlib.h>
}

#include "PlayScreen.h"
#include "BrowserScreen.h"

using namespace MAUtil;
using namespace MAUI;
using namespace MAInterpreter;

// ====== Global variables visible in this file ======

static int TitleBarHeight = 40;
static int ButtonBarHeight = 30;
static int ItemHeight = 30; //25;
static int NavigationBoxHeight = ItemHeight * 2;
static int WidgetPadding = 4;
static int TitlePadding = 4;
static int ButtonPadding = 6;

static int TitleBarColor = 0x00CC00;
static int NavigationBoxTitleColor = 0x00AA00;
static int NavigationBoxUrlColor = 0x000055;
static int ScriptBoxTitleColor = 0x00AA00;
static int ScriptBoxColor = 0x000055;
static int ScriptItemColor = 0x00CC00;
static int SelectedColor = 0x00CC00;
static int DeselectedColor = 0x000055;
static int ButtonColor1 = 0x00AA00;
static int ButtonColor2 = 0x00CC00;
static int ButtonColor3 = 0x00AA00;

static Font* TitleBarFont;
static Font* LabelFont;
static Font* TextFont;
static Font* ButtonFont;

static char* TitleBarText = "Lua App Browser";
static char* NavigationBoxTitle = "App URL:";
static char* ScriptBoxTitle = "My Apps:";
//static char* ScriptBoxEmptyText = "(No script loaded)";
//static char* DefaultScriptUrl = "http://comikit.se/mobilelua/scripts/LuaPaint.lua";
//static char* DefaultScriptUrl = "http://divineprogrammer.blogspot.com/2010/10/mobile-lua.html";
//static char* DefaultScriptUrl = "http://127.0.0.1:4042/mobilelua/scripts/Playspace.lua";
static char* DefaultScriptUrl = "http://10.0.2.2:4042/mobilelua/scripts/LuaPaint.lua";
static char* RunButtonText = "Run";
static char* MenuButtonText = "UrlBox";
static char* ExitButtonText = "Exit";
//static char* LoadingScript = "Loading app";
//static char* ScriptCouldNotBeLoaded = "App could not be loaded";
static wchar* TextBoxTitle = L"Enter App URL";
static wchar* TextBoxDefaultText = L"http://comikit.se/mobilelua/scripts/LuaPaint.lua";


// ====== Methods in class BrowserScreen ======

BrowserScreen::BrowserScreen(BrowserMoblet* moblet)
{
	this->moblet = moblet;

	// TODO: Make these instance variables.
	TitleBarFont = Sys()->getFont("Arial32BoldWhite");
	LabelFont = Sys()->getFont("Arial20BoldWhite");
	TextFont = Sys()->getFont("Arial20BoldWhite");
	ButtonFont = Sys()->getFont("Arial20BoldWhite");

	Widget* titleBar = createTitleBar();
	Widget* navigationBox = createNavigationBox();
	Widget* scriptBox = createScriptBox();
	Widget* buttonBar = createButtonBar();

	urlEditBox = getUrlEditBox(navigationBox);
	scriptListBox = getScriptListBox(scriptBox);
	runButton = getRunButton(buttonBar);
	menuButton = getMenuButton(buttonBar);
	exitButton = getExitButton(buttonBar);

	mainLayout = createMainLayout();
	mainLayout->add(titleBar);
	mainLayout->add(navigationBox);
	mainLayout->add(scriptBox);
	mainLayout->add(buttonBar);

	addNavigationItem("LuaPaint (blog page)", "http://divineprogrammer.blogspot.com/2010/10/mobile-lua.html");
	addNavigationItem("LuaPaint", "http://comikit.se/mobilelua/scripts/LuaPaint.lua");
	addNavigationItem("Animated Rectangle", "http://comikit.se/mobilelua/scripts/AnimatedRectangle.lua");
	//addNavigationItem("Pong", "http://mobilelua.googlecode.com/svn/trunk/scripts/Pong.lua");
	//addNavigationItem("Colors", "http://comikit.se/mobilelua/scripts/Colors.lua");

	urlEditBox->addWidgetListener(this);

	this->setMain(mainLayout);
}

BrowserScreen::~BrowserScreen()
{
/*
	if (downloader)
	{
		delete downloader;
		downloader = NULL;
	}
*/
	if (getMain())
	{
		delete getMain();
	}
}

void BrowserScreen::selectionChanged(Widget *widget, bool selected)
{
	lprintfln("BrowserScreen::selectionChanged");

	if (selected)
	{
		widget->setBackgroundColor(SelectedColor);
	}
	else
	{
		widget->setBackgroundColor(DeselectedColor);
	}
}

void BrowserScreen::show()
{
	//scriptListBox->getChildren()[((ListBox*)scriptListBox)->getSelectedIndex()]->setSelected(true);
	urlEditBox->setSelected(true);
	Screen::show();
}

void BrowserScreen::hide()
{
	scriptListBox->getChildren()[((ListBox*)scriptListBox)->getSelectedIndex()]->setSelected(false);
	urlEditBox->setSelected(false);
	Screen::hide();
}

void BrowserScreen::selectPrevious()
{
	ListBox* listBox = (ListBox*)scriptListBox;

	if (0 >= listBox->getChildren().size())
	{
		return;
	}

	int lastItemIndex = listBox->getChildren().size() - 1;
	Widget* firstItem = listBox->getChildren()[0];
	Widget* lastItem = listBox->getChildren()[lastItemIndex];

	if (urlEditBox->isSelected())
	{
		// Select last list item.
		lastItem->setSelected(true);
		listBox->setSelectedIndex(lastItemIndex);
		urlEditBox->setSelected(false);
	}
	else if (firstItem->isSelected())
	{
		// Select edit box.
		firstItem->setSelected(false);
		urlEditBox->setSelected(true);
	}
	else
	{
		// Select previous list item.
		listBox->selectPreviousItem();
	}
}

void BrowserScreen::selectNext()
{
	ListBox* listBox = (ListBox*)scriptListBox;

	if (0 >= listBox->getChildren().size())
	{
		return;
	}

	Widget* firstItem = listBox->getChildren()[0];
	Widget* lastItem = listBox->getChildren()[listBox->getChildren().size() - 1];

	if (urlEditBox->isSelected())
	{
		// Select first list item.
		firstItem->setSelected(true);
		listBox->setSelectedIndex(0);
		urlEditBox->setSelected(false);
	}
	else if (lastItem->isSelected())
	{
		// Select edit box.
		lastItem->setSelected(false);
		urlEditBox->setSelected(true);
	}
	else
	{
		// Select next list item.
		listBox->selectNextItem();
	}
}

void BrowserScreen::keyPressEvent(int keyCode, int nativeCode)
{
	switch (keyCode)
	{
		case MAK_UP:
			selectPrevious();
			break;
		case MAK_DOWN:
			selectNext();
			break;
		case MAK_FIRE:
			runSelectedScript();
			break;
		case MAK_BACK:
		case MAK_SOFTLEFT:
			exitApp();
			break;
		case MAK_SOFTRIGHT:
			openTextBox();
			break;
		default:
			lprintfln("Key code: %i", keyCode);
			break;
	}
}

void BrowserScreen::pointerPressEvent(MAPoint2d point)
{
	if (urlEditBox->contains(point.x, point.y))
	{
		// Bring up a text box.
		openTextBox();
	}
	else if (runButton->contains(point.x, point.y))
	{
		runSelectedScript();
	}
	else if (menuButton->contains(point.x, point.y))
	{
		openTextBox();
	}
	else if (exitButton->contains(point.x, point.y))
	{
		exitApp();
	}
	else if (scriptListBox->contains(point.x, point.y))
	{
		Widget* item = scriptListBox->widgetAt(point.x, point.y);
		if (NULL != item)
		{
			String* url = urls[(int)item];
			if (NULL != url)
			{
				lprintfln("Item picked: %s", url->c_str());
				runScript(url->c_str());
			}
		}
	}
}

void BrowserScreen::openTextBox()
{
	int result = maTextBox(
		TextBoxTitle,
		TextBoxDefaultText,
		textBoxResult,
		TEXTBOX_RESULT_CAPACITY,
		MA_TB_TYPE_ANY);
	if (IOCTL_UNAVAILABLE == result)
	{
		lprintfln("maTextBox is not available");
	}
	else
	{
		moblet->setTextBoxListener(this);
		lprintfln("maTextBox opened");
	}
}

void BrowserScreen::handleTextBoxResult(int textBoxResultLength)
{
	lprintfln("handleTextBoxResult textBoxResultLength: %i", textBoxResultLength);

	// Set the urlEditBox text to the textbox text.
	String text;
	for (int i = 0; i < textBoxResultLength; ++i)
	{
		text += ((char)textBoxResult[i]);
	}
	((EditBox*)urlEditBox)->setText(text);
}

void BrowserScreen::runSelectedScript()
{
	// Check if the edit box is selected and if so
	// run the script of its url.
	if (urlEditBox->isSelected())
	{
		runUrlEditBoxScript();
	}
	else
	{
		runScriptListBoxScript();
	}
}

void BrowserScreen::runUrlEditBoxScript()
{
	// Get url.
	const String& url = ((EditBox*)urlEditBox)->getText();
	lprintfln("runSelectedScript: %s", url.c_str());

	// We want to add the url to list box if not present.

	// Find out if it is there.
	ListBox* listBox = (ListBox*)scriptListBox;
	int size = listBox->getChildren().size();
	bool found = false;
	for (int i = 0; i < size; ++i)
	{
		Widget* item = listBox->getChildren()[i];
		String* itemUrl = urls[(int)item];
		if (NULL != itemUrl)
		{
			if (0 == strcmp(url.c_str(), itemUrl->c_str()))
			{
				// Items are equal, this url is already in the listbox.
				found = true;
				break;
			}
		}
	}

	// If we got here, the url is not in the list, so add it.
	if (!found)
	{
		int startIndex = url.findLastOf('/');
		if (startIndex > 0)
		{
			startIndex += 1;
			String fileName = url.substr(startIndex, url.length() - startIndex);
			addNavigationItem(fileName, url);
		}
	}

	// Run script.
	runScript(url.c_str());
}

void BrowserScreen::runScriptListBoxScript()
{
	// Get selected list item.
	ListBox* listBox = (ListBox*)scriptListBox;
	int selectedItemIndex = listBox->getSelectedIndex();
	if (0 <= selectedItemIndex)
	{
		Widget* selectedItem = listBox->getChildren()[selectedItemIndex];
		if (NULL != selectedItem)
		{
			String* url = urls[(int)selectedItem];
			if (NULL != url)
			{
				lprintfln("runSelectedScript: %s", url->c_str());
				runScript(url->c_str());
			}
		}
	}
}

void BrowserScreen::runScript(const String& url)
{
	// Create PlayScreen, load and run.
	PlayScreen* playScreen = new PlayScreen(this);
	playScreen->show();
	playScreen->setInterpreter(new LuaInterpreter());
	playScreen->setScriptURL(url);
	playScreen->loadAndRun();
}

void BrowserScreen::exitApp()
{
	moblet->closeEvent();
	moblet->close();
}

Layout* BrowserScreen::createMainLayout()
{
	Layout* layout = new Layout(
		0,
		0,
		Sys()->getScreenWidth(),
		Sys()->getScreenHeight(),
		NULL,
		1,
		4);
	return layout;
}

Widget* BrowserScreen::createTitleBar()
{
	Label* label = new Label(
		0,
		0,
		Sys()->getScreenWidth(),
		TitleBarHeight,
		NULL,
		TitleBarText,
		TitleBarColor,
		TitleBarFont);
	setTitlePadding(label);

	return label;
}

Widget* BrowserScreen::createNavigationBox()
{
	Layout* layout = new Layout(
		0,
		0,
		Sys()->getScreenWidth(),
		ItemHeight * 2,
		NULL,
		1,
		2);

	Label* label = new Label(
		0,
		0,
		Sys()->getScreenWidth(),
		ItemHeight,
		layout,
		NavigationBoxTitle,
		NavigationBoxTitleColor,
		LabelFont);
	setPadding(label);

	EditBox *editBox = new EditBox(
		0,
		0,
		Sys()->getScreenWidth(),
		ItemHeight,
		layout,
		DefaultScriptUrl,
		DeselectedColor,
		TextFont,
		true,
		false,
		200);
	setPadding(editBox);

	//editBox->setDrawBackground(false);
	//editBox->setSelected(true);
	//editBox->setAutoSizeY(true);
	//editBox->setMultiLine(true);

	return layout;
}

Widget* BrowserScreen::createScriptBox()
{
	Label* label;

	// Layout holds title label and a listbox.
	Layout* layout = new Layout(
		0,
		0,
		Sys()->getScreenWidth(),
		Sys()->getScreenHeight() - (TitleBarHeight + NavigationBoxHeight + ButtonBarHeight),
		NULL,
		1,
		2);

	// Title label.
	label = new Label(
		0,
		0,
		Sys()->getScreenWidth(),
		ItemHeight,
		layout,
		ScriptBoxTitle,
		ScriptBoxTitleColor,
		LabelFont);
	setPadding(label);

	// Listbox.
	ListBox* scriptListBox = new ListBox(
		0,
		0,
		Sys()->getScreenWidth(),
		Sys()->getScreenHeight() - (TitleBarHeight + NavigationBoxHeight + ButtonBarHeight + ItemHeight),
		layout,
		ListBox::LBO_VERTICAL,
		ListBox::LBA_LINEAR,
		true);
	scriptListBox->setBackgroundColor(ScriptBoxColor);
	setPadding(scriptListBox);

	return layout;
}

Widget* BrowserScreen::createButtonBar()
{
	Layout* layout = new Layout(
		0,
		0,
		Sys()->getScreenWidth(),
		ButtonBarHeight,
		NULL,
		3,
		1);

	Label* exitButton = new Label(
		0,
		0,
		Sys()->getScreenWidth() / 3,
		ButtonBarHeight,
		layout,
		ExitButtonText,
		ButtonColor1,
		ButtonFont);
	exitButton->setHorizontalAlignment(Label::HA_LEFT);
	setButtonPadding(exitButton);

	Label* runButton = new Label(
		0,
		0,
		Sys()->getScreenWidth() / 3,
		ButtonBarHeight,
		layout,
		RunButtonText,
		ButtonColor2,
		ButtonFont);
	runButton->setHorizontalAlignment(Label::HA_CENTER);
	setButtonPadding(runButton);

	Label* menuButton = new Label(
		0,
		0,
		Sys()->getScreenWidth() / 3,
		ButtonBarHeight,
		layout,
		MenuButtonText,
		ButtonColor1,
		ButtonFont);
	menuButton->setHorizontalAlignment(Label::HA_RIGHT);
	setButtonPadding(menuButton);

	return layout;
}

void BrowserScreen::addNavigationItem(const String& title, const String& url)
{
	Label* label = new Label(0, 0, Sys()->getScreenWidth(), ItemHeight, NULL, title, DeselectedColor, LabelFont);
	//label->setAutoSizeX();
	scriptListBox->add(label);
	setPadding(label);
	label->addWidgetListener(this);
	urls.insert((int)label, new String(url));
}

Widget* BrowserScreen::getUrlEditBox(Widget* navigationBox)
{
	return navigationBox->getChildren()[1];
}

Widget* BrowserScreen::getScriptListBox(Widget* scriptBox)
{
	return scriptBox->getChildren()[1];
}

Widget* BrowserScreen::getExitButton(Widget* buttonBar)
{
	return buttonBar->getChildren()[0];
}

Widget* BrowserScreen::getRunButton(Widget* buttonBar)
{
	return buttonBar->getChildren()[1];
}

Widget* BrowserScreen::getMenuButton(Widget* buttonBar)
{
	return buttonBar->getChildren()[2];
}

void BrowserScreen::setPadding(Widget *w)
{
	w->setPaddingLeft(WidgetPadding);
	w->setPaddingBottom(WidgetPadding);
	w->setPaddingRight(WidgetPadding);
	w->setPaddingTop(WidgetPadding);
}

void BrowserScreen::setTitlePadding(Widget *w)
{
	w->setPaddingLeft(WidgetPadding);
	w->setPaddingBottom(TitlePadding);
	w->setPaddingRight(WidgetPadding);
	w->setPaddingTop(TitlePadding);
}

void BrowserScreen::setButtonPadding(Widget *w)
{
	w->setPaddingLeft(ButtonPadding);
	w->setPaddingBottom(ButtonPadding);
	w->setPaddingRight(ButtonPadding);
	w->setPaddingTop(ButtonPadding);
}

/*
	listBox = new ListBox(
		0,
		0,
		The::system()->getScreenWidth(),
		The::system()->getScreenHeight(),
		NULL,
		ListBox::LBO_VERTICAL,
		ListBox::LBA_LINEAR,
		true);
*/
/*
 * How to make a multiline editbox.
 *
 * EditBox *editBox = new EditBox(
	0,
	0, //20,
	The::system()->getScreenWidth(),
	50,
	listBox, //label,
	"http://comikit.se/TinyJS/Bounce.jsp",
	0,
	The::system()->getFont(),
	true,
	false);
editBox->setDrawBackground(false);
editBox->setSelected(true);
editBox->setAutoSizeY(true);
editBox->setMultiLine(true);*/

//label->addWidgetListener(this);
